package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.LoginDto;
import com.zzyl.dto.UserDto;
import com.zzyl.entity.Resource;
import com.zzyl.entity.User;
import com.zzyl.entity.UserRole;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeptMapper;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.properties.JwtTokenManagerProperties;
import com.zzyl.properties.SecurityConfigProperties;
import com.zzyl.service.UserService;
import com.zzyl.utils.NoProcessing;
import com.zzyl.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {


    @Autowired
    private UserMapper userMapper;

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private ResourceMapper resourceMapper;

    @Autowired
    private SecurityConfigProperties securityConfigProperties;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private JwtTokenManagerProperties jwtTokenManagerProperties;
    /**
     * 用户分页查询
     *
     * @param userDto
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    @Cacheable(value = "user:page",key = "#userDto.hashCode()")
    public PageResponse<UserVo> page(UserDto userDto, Integer pageNum, Integer pageSize) {
        userDto.setDeptNo(NoProcessing.processString(userDto.getDeptNo()));
        PageHelper.startPage(pageNum,pageSize);
        Page<UserVo> page = userMapper.page(userDto);
        List<UserVo> list = page.getResult();
        list.forEach(item->{
           List<Map<String,String>> roles = userMapper.selectRoleLabels(item.getId());
            Set<String> roleLabels = new HashSet<>();
            Set<String> roleIds = new HashSet<>();
            for (Map<String, String> role : roles) {
                roleLabels.add(role.get("roleName"));
                roleIds.add(String.valueOf(role.get("roleId")));
            }
            item.setRoleLabels(roleLabels);
            item.setRoleVoIds(roleIds);
        });
        PageResponse<UserVo> pageResponse = PageResponse.of(page, UserVo.class);
        return pageResponse;
    }

    /**
     * 新增用户
     *
     * @param userDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "user:page",allEntries = true)
    public void insert(UserDto userDto) {
        //查询传过来的部门是否是最底层的部门
        String parentDeptNumber = NoProcessing.processString(userDto.getDeptNo());
//        Integer count = deptMapper.selectChildren(userDto.getDeptNo());
        Integer count = deptMapper.selectChildren(parentDeptNumber);
        if (count > 0){
            throw new BaseException(BasicEnum.USER_LOCATED_BOTTOMED_DEPT);
        }
        User user = BeanUtil.toBean(userDto, User.class);
        //插入基本数据
        user.setPassword(BCrypt.hashpw("888itcast.CN764%..."));
        user.setDataState(SuperConstant.DATA_STATE_0);
        user.setUsername(userDto.getEmail());
        user.setNickName(userDto.getRealName());
        userMapper.insert(user);
        //设置初始登录密码

        //根据主键回显的ID插入关联表
        //构建用户角色对象
        List<UserRole> userRoles = new ArrayList<>();
        //对userRoles的元素进行赋值
        userDto.getRoleVoIds().forEach(item->{
            UserRole userRole = new UserRole();
            userRole.setUserId(user.getId());
            userRole.setRoleId(Long.valueOf(item));
            userRole.setDataState(SuperConstant.DATA_STATE_0);
             userRoles.add(userRole);
        });
        userMapper.batchInserts(userRoles);
    }

    /**
     * 更新用户
     *
     * @param userDto
     */
    @Override
    @Transactional
    @CacheEvict(value = "user:page",allEntries = true)
    public void update(UserDto userDto) {
        //对基础表中的字段进行更新
        User user = BeanUtil.toBean(userDto, User.class);
        userMapper.update(user);
        //根据用户ID删除role中的所有关联项
        userMapper.deleteByUserId(user.getId());
        //批量插入员工的相关职位
        List<UserRole> userRoles = new ArrayList<>();
        //对userRoles的元素进行赋值
        userDto.getRoleVoIds().forEach(item->{
            UserRole userRole = new UserRole();
            userRole.setUserId(user.getId());
            userRole.setRoleId(Long.valueOf(item));
            userRole.setDataState(SuperConstant.DATA_STATE_0);
            userRoles.add(userRole);
        });
        userMapper.batchInserts(userRoles);
    }

    /**
     * 启用禁用
     *
     * @param id
     * @param status
     */
    @Override
    @CacheEvict(value = "user:page",allEntries = true)
    public void isEnable(Long id, Integer status) {
        userMapper.isEnable(id,status);
    }

    /**
     * 删除用户
     *
     * @param userIds
     */
    @Override
    @Transactional
    @CacheEvict(value = "user:page",allEntries = true)
    public void deleteById(Long userIds) {
        //删除基础表中的数据
        userMapper.delete(userIds);
        //删除关联表中的数据
        userMapper.deleteByUserId(userIds);
    }

    /**
     * 用户登录
     *
     * @param loginDto
     * @return
     */
    @Override
    public UserVo login(LoginDto loginDto) {
        //通过用户名查询对应的用户
        UserVo userVo = userMapper.getByUserName(loginDto.getUsername());
        //判断用户是否存在，不存在抛异常
        if (userVo == null){
            throw new BaseException(BasicEnum.LOGIN_FAIL);
        }
        //判断用户状态
        if (userVo.getDataState().equals(SuperConstant.DATA_STATE_1)){
            throw new BaseException(BasicEnum.STATE_LOSE_EFFICACY);
        }
        //比对密码
        if (!BCrypt.checkpw(loginDto.getPassword(),userVo.getPassword())){
            //密码不匹配，抛出异常
            throw new BaseException(BasicEnum.LOGIN_FAIL_PASSWORD);
        }
        //将密码制空,密码脱敏
        userVo.setPassword(null);

        //获取当前用户对应的资源列表
        List<String> urlList = resourceMapper.selectListByUserId(userVo.getId());

        //获取白名单url列表
        List<String> publicAccessUrls = securityConfigProperties.getPublicAccessUrls();
        urlList.addAll(publicAccessUrls);

        redisTemplate.opsForValue().set(SuperConstant.PUBLIC_ACCESS_URLS +userVo.getId(), JSONUtil.toJsonStr(urlList),
               jwtTokenManagerProperties.getTtl() /1000, TimeUnit.SECONDS);
        return userVo;
    }

    /**
     * 查询所有用户
     *
     * @param userDto
     * @return
     */
    @Override
    @Cacheable(value = "user:list",key = "#userDto.hashCode()")
    public List<UserVo> list(UserDto userDto) {
        return userMapper.list(userDto);
    }
}
